# # # # link/scheduler.py
# # # # import time
# # # # import threading
# # # # import random
# # # # from link.tasks import run_link_task

# # # # class TaskScheduler:
# # # #     def __init__(self):
# # # #         self.threads = {}
# # # #         self.running = True

# # # #     def start_task(self, task_id, delay):
# # # #         def loop():
# # # #             while self.running:
# # # #                 run_link_task.delay(task_id)
# # # #                 time.sleep(delay * 60 + random.randint(1, 60))
# # # #         t = threading.Thread(target=loop)
# # # #         t.start()
# # # #         self.threads[task_id] = t

# # # #     def stop_all(self):
# # # #         self.running = False
# # # #         for t in self.threads.values():
# # # #             t.join()
# # import time
# # import threading
# # import random
# # from processutil.tasks import run_link_task

# # class TaskScheduler:
# #     def __init__(self):
# #         self.threads = {}           # 任务ID -> 线程对象
# #         self.stop_flags = {}        # 任务ID -> threading.Event

# #     def start_task(self, task_id, delay):
# #         if task_id in self.threads:
# #             pass
# #             #print(f"任务 {task_id} 已存在")
# #             return

# #         stop_flag = threading.Event()
# #         self.stop_flags[task_id] = stop_flag

# #         def loop():
# #             pass
# #             #print(f"任务 {task_id} 启动，间隔 {delay} 分钟")
# #             while not stop_flag.is_set():
# #                 pass
# #                 #print(f"执行任务 {task_id}")
# #                 run_link_task.delay(task_id)
# #                 time.sleep(delay * 60 + random.randint(1, 60))  # 随机延迟

# #         t = threading.Thread(target=loop)
# #         t.start()
# #         self.threads[task_id] = t

# #     def stop_task(self, task_id):
# #         if task_id not in self.threads:
# #             pass
# #             #print(f"任务 {task_id} 不存在")
# #             return

# #         pass
# #         #print(f"停止任务 {task_id}")
# #         self.stop_flags[task_id].set()
# #         self.threads[task_id].join()
# #         del self.threads[task_id]
# #         del self.stop_flags[task_id]

# #     def stop_all(self):
# #         pass
# #         #print("停止所有任务")
# #         for task_id in list(self.threads.keys()):
# #             self.stop_task(task_id)

# import time
# import threading
# import random as rand_module  # 重命名导入避免冲突
# from processutil.tasks import run_link_task

# class TaskScheduler:
    
#     def __init__(self):
#         self.threads = {}        # task_id -> Thread
#         self.stop_flags = {}     # task_id -> threading.Event()

#     def start_task(self, task_id, delay):
#         stop_event = threading.Event()

#         def loop():
#             while not stop_event.is_set():
#                 run_link_task.delay(task_id)
#                 if stop_event.is_set():
#                     break
#                 # 使用明确的模块名调用randint
#                 time.sleep(delay * 60 + rand_module.randint(1, 60))
#                 # for _ in range(delay * 60):  # 分钟延迟精度
#                 #     if stop_event.is_set():
#                 #         break
#                 #     time.sleep(1 + rand_module.randint(0, 1))  # 轻微抖动，防止同步触发

#         t = threading.Thread(target=loop, daemon=True)
#         t.start()

#         self.threads[task_id] = t
#         self.stop_flags[task_id] = stop_event

#     def stop_task(self, task_id):
#         if task_id in self.stop_flags:
#             self.stop_flags[task_id].set()
#             # 不调用 join，这样不会阻塞 web 请求
#             del self.stop_flags[task_id]
#             del self.threads[task_id]
    
#     def stop_all(self):
#         """停止所有任务"""
#         for task_id in list(self.threads.keys()):
#             self.stop_task(task_id)

import time
import threading
import random as rand_module
import redis
import json
from processutil.tasks import run_link_task
from django.conf import settings
from celery import current_app

class TaskScheduler:
    _instance = None
    _lock = threading.Lock()
    _redis_lock_key = "scheduler_lock"
    _redis_tasks_key = "scheduler_tasks"

    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super(TaskScheduler, cls).__new__(cls)
                    cls._instance._initialized = False
        return cls._instance

    def __init__(self):
        if not self._initialized:
            with self._lock:
                if not self._initialized:
                    self.redis_client = redis.Redis(
                        host=settings.REDIS_HOST,
                        port=settings.REDIS_PORT,
                        db=settings.REDIS_DB
                    )
                    self._initialized = True

    def _acquire_lock(self):
        return self.redis_client.set(
            self._redis_lock_key,
            '1',
            ex=60,
            nx=True
        )

    def _release_lock(self):
        self.redis_client.delete(self._redis_lock_key)

    def _get_task_info(self, task_id):
        task_info = self.redis_client.hget(self._redis_tasks_key, str(task_id))
        return json.loads(task_info) if task_info else None

    def _set_task_info(self, task_id, info):
        self.redis_client.hset(
            self._redis_tasks_key,
            str(task_id),
            json.dumps(info)
        )

    def _remove_task_info(self, task_id):
        self.redis_client.hdel(self._redis_tasks_key, str(task_id))

    def start_task(self, task_id, delay):
        # 先清理可能存在的旧任务状态
        self._remove_task_info(task_id)

        if not self._acquire_lock():
            return

        try:
            task_info = {
                'status': 'running',
                'delay': delay,
                'start_time': time.time(),
                'last_run': None,
                'next_run': time.time()
            }
            self._set_task_info(task_id, task_info)

            # 启动第一次任务
            run_link_task.delay(task_id)
        finally:
            self._release_lock()

    def stop_task(self, task_id):
        # 确保完全清理任务状态
        self._remove_task_info(task_id)

    def stop_all(self):
        all_tasks = self.redis_client.hgetall(self._redis_tasks_key)
        for task_id in all_tasks:
            self.stop_task(task_id)

    def is_task_running(self, task_id):
        task_info = self._get_task_info(task_id)
        return task_info and task_info['status'] == 'running'

    def get_all_tasks(self):
        all_tasks = self.redis_client.hgetall(self._redis_tasks_key)
        return {
            task_id.decode(): json.loads(task_info)
            for task_id, task_info in all_tasks.items()
        }